# file: unbind_assertion.py
import time

from pywinauto import Desktop

from tools.logger import log_info, log_error


class UnbindAssertion:
    """
    专门用于断言【解绑】操作结果的工具类。
    注意：解绑操作必定会弹出 '条码关联系统-提示' 窗口，需根据窗口内文本判断成功或失败。
    """

    @staticmethod
    def assert_unbind_success(timeout=5):
        """
        断言：解绑成功（弹窗中包含“解绑成功”等关键词）
        :param timeout: 等待弹窗出现的超时时间
        """
        dialog = UnbindAssertion._wait_for_dialog(timeout)
        full_text = UnbindAssertion._get_dialog_message(dialog)

        log_info(f"📋 解绑结果提示内容: {full_text}")

        # ✅ 成功关键词
        success_keywords = ["解绑成功", "已解绑", "操作成功"]
        if any(kw in full_text for kw in success_keywords):
            log_info("✅ 解绑成功！")
        else:
            log_error(f"❌ 预期解绑成功，但提示信息不符合 → '{full_text}'")
            UnbindAssertion._close_dialog(dialog)  # 先关闭再抛异常
            raise AssertionError(f"解绑未成功，实际提示: {full_text}")

        UnbindAssertion._close_dialog(dialog)

    @staticmethod
    def assert_unbind_failure(expected_reason=None, timeout=5):
        """
        断言：解绑失败（弹窗中包含失败关键词）
        :param expected_reason: 预期失败类型，可选值：
                                - 'not_found'           -> 无关联记录
                                - 'already_unbound'     -> 已解绑/重复解绑
                                - 'permission_denied'   -> 权限不足
                                - 'format_error'        -> 条码格式错误
                                - 'mismatch'            -> 工单/项目不匹配
                                - 'general_failure'     -> 其他通用失败
        :param timeout: 超时时间
        """
        dialog = UnbindAssertion._wait_for_dialog(timeout)
        full_text = UnbindAssertion._get_dialog_message(dialog)

        log_info(f"📋 解绑结果提示内容: {full_text}")

        # ❌ 失败类型关键词映射
        failure_types = {
            "not_found": "未查询到该条码|无关联记录|不存在|未找到",
            "already_unbound": "已解绑|不允许重复解绑|无需解绑|只能解绑一次",
            "permission_denied": "权限不足|需要管理员权限|授权失败|密钥错误",
            "format_error": "条码格式不正确|条码长度错误|非法字符|条码不合法",
            "mismatch": "工单号不匹配|项目号不匹配|不属于当前工单|不一致",
            "general_failure": "失败|错误|异常|操作无效|系统异常|不允许"
        }

        matched_type = None
        for key, keywords in failure_types.items():
            if any(kw in full_text for kw in keywords.split('|')):
                matched_type = key
                break

        if matched_type:
            log_info(f"🔍 识别到失败类型: {matched_type}")
        else:
            log_info("⚠️ 未识别到标准失败类型")

        # 验证预期失败类型
        if expected_reason:
            if expected_reason not in failure_types:
                raise ValueError(f"不支持的 expected_reason: {expected_reason}")
            expected_keywords = failure_types[expected_reason].split('|')
            if not any(kw in full_text for kw in expected_keywords):
                UnbindAssertion._close_dialog(dialog)
                raise AssertionError(
                    f"❌ 预期失败类型 '{expected_reason}'，但实际提示不匹配。\n"
                    f"预期包含: {expected_keywords}\n"
                    f"实际内容: {full_text}"
                )

        log_info("✅ 断言通过！解绑失败（符合预期）")
        UnbindAssertion._close_dialog(dialog)

    @staticmethod
    def _wait_for_dialog(timeout=5):
        """等待‘条码关联系统-提示’弹窗出现"""
        desktop = Desktop(backend='win32')
        dialog = desktop.window(title="条码关联系统-提示")
        if not dialog.exists(timeout=timeout):
            raise AssertionError("❌ 解绑后未出现预期的提示弹窗")
        dialog.wait('visible', timeout=timeout)
        log_info("🟡 检测到【条码关联系统-提示】弹窗")
        return dialog

    @staticmethod
    def _get_dialog_message(dialog):
        """提取弹窗中所有非空文本"""
        texts = [
            e.window_text().strip()
            for e in dialog.descendants(auto_id='Tiplbl')
            if e.window_text().strip()
        ]
        return "\n".join(texts).replace('\n\n', '\n').strip()

    @staticmethod
    def _close_dialog(dialog):
        """点击【确定】按钮关闭弹窗"""
        try:
            confirm_btn = dialog.child_window(title="确定", auto_id="okbtn")
            if confirm_btn.wait('visible', timeout=5):
                confirm_btn.click_input()
                time.sleep(0.2)
                log_info("✅ 已点击【确定】关闭弹窗")
            else:
                log_error("⚠️ 【确定】按钮未找到")
        except Exception as e:
            log_error(f"⚠️ 关闭弹窗失败: {e}")